/*
 * jsonrpc-c.c
 *
 *  Created on: Oct 11, 2012
 *      Author: hmng
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include "jsonrpc-c.h"

#include "mongoose.h"

struct jrpc_server my_server;
void jrpc_http_handler(struct mg_connection *c, struct mg_http_message *hm);

/**
 * @brief HTTP Server事件处理函数
 * 
 * @param c         接收事件的连接 
 * @param ev        事件编号
 * @param ev_data   事件数据
 * @param fn_data   
 */
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) 
{
  
  if (ev == MG_EV_HTTP_MSG) 
  {
        struct mg_http_message *http_massage_data = ev_data;
        if (mg_http_match_uri(http_massage_data, "/api/jrpc"))
        {
            jrpc_http_handler(c, http_massage_data);
        }
        else
        {
            struct mg_http_serve_opts opts = {.root_dir = "./web"};   // Serve local dir
            mg_http_serve_dir(c, http_massage_data, &opts);
        }
  }
    
}

void jrpc_http_handler(struct mg_connection *c, struct mg_http_message *hm)
{    
	cJSON *result = cJSON_CreateObject();
	char *str_ptr = 0;
	char RequestMethod[12];
	memset(RequestMethod,0x00,12);
	strncpy(RequestMethod,hm->method.ptr,hm->method.len);
	if (strcmp(RequestMethod,"POST")==0)
	{
		//获取HTTP正文
    	cJSON *root = cJSON_Parse(hm->body.ptr);
		if (root != NULL)
		{
			if (root->type == cJSON_Object)
			{
				//获取 method、params、id
				cJSON *method = cJSON_GetObjectItem(root,"method");
				cJSON *params = cJSON_GetObjectItem(root,"params");
				cJSON *id     = cJSON_GetObjectItem(root,"id");

				if (method != NULL && params != NULL && id != NULL)
				{
					char *name = method->valuestring;
					cJSON *returned = NULL;
					int procedure_found = 0;
					jrpc_context ctx;
					ctx.error_code = 0;
					ctx.error_message = NULL;
					int i = my_server.procedure_count;
					while (i--) {
						if (!strcmp(my_server.procedures[i].name, name)) {
							procedure_found = 1;
							ctx.data = my_server.procedures[i].data;
							returned = my_server.procedures[i].function(&ctx, params, id);
							break;
						}
					}
					if (!procedure_found)
					{
						cJSON_AddItemToObject(result,"sys-error",cJSON_CreateString("101"));
						cJSON_AddItemToObject(result,"error-describe",cJSON_CreateString("Methon not found."));
					}
					else {					
						cJSON_AddItemToObject(result,"result",returned);
						cJSON_AddItemToObject(result,"sys-error",cJSON_CreateString("000"));
					}
					if (id->type == cJSON_String)
						cJSON_AddItemToObject(result,"id",cJSON_CreateString(id->valuestring));
					else if (id->type == cJSON_Number)
						cJSON_AddItemToObject(result,"id",cJSON_CreateNumber(id->valueint));
					else
						cJSON_AddItemToObject(result,"id",cJSON_CreateString("None"));				
				}
				else
				{
					cJSON_AddItemToObject(result,"sys-error",cJSON_CreateString("102"));
					cJSON_AddItemToObject(result,"error-describe",cJSON_CreateString("Request Format Invalid."));
				}
			}  
		//删除root json
		cJSON_Delete(root);      
		}
		else
		{
			cJSON_AddItemToObject(result,"sys-error",cJSON_CreateString("102"));
			cJSON_AddItemToObject(result,"error-describe",cJSON_CreateString("Request Format Invalid."));
		}	
	}
	else
	{
		cJSON_AddItemToObject(result,"sys-error",cJSON_CreateString("103"));
		cJSON_AddItemToObject(result,"error-describe",cJSON_CreateString("Request Method Invalid, Please Use POST Method."));

	}
    
	str_ptr = cJSON_Print(result);
	cJSON_Delete(result);
	//返回响应
	mg_http_reply(c,200, "Content-Type: application/json\r\n","%s",str_ptr);
	free(str_ptr);
}

void *HTTP_MainThread(void *arg)
{
    struct mg_mgr mgr;

    mg_mgr_init(&mgr);
	printf("Server listen on port 8000\r\n");
    mg_http_listen(&mgr, "0.0.0.0:8000", fn, NULL);     // Create listening connection
    while (1)
    {
        mg_mgr_poll(&mgr, 100);                        // Block forever
    }     
}

////////////////////////////////////////////////////////////////////////////////
//JRPC 方法管理与注册
////////////////////////////////////////////////////////////////////////////////
static void jrpc_procedure_destroy(struct jrpc_procedure *procedure);

//jrpc初始化函数
int jrpc_server_init(struct jrpc_server *server) {
    return jrpc_server_init_with_ev_loop(server);
}


//使用eventloop初始化server
int jrpc_server_init_with_ev_loop(struct jrpc_server *server) {
	//清空jrpc_server结构体
	memset(server, 0, sizeof(struct jrpc_server));
	
	char * debug_level_env = getenv("JRPC_DEBUG");
	if (debug_level_env == NULL)
		server->debug_level = 0;
	else {
		server->debug_level = strtol(debug_level_env, NULL, 10);
		printf("JSONRPC-C Debug level %d\n", server->debug_level);
	}
	//启动jrpc server
	return 0;
}


// Make the code work with both the old (ev_loop/ev_unloop)
// and new (ev_run/ev_break) versions of libev.
#ifdef EVUNLOOP_ALL
  #define EV_RUN ev_loop
  #define EV_BREAK ev_unloop
  #define EVBREAK_ALL EVUNLOOP_ALL
#else
  #define EV_RUN ev_run
  #define EV_BREAK ev_break
#endif

u_int8_t JRPC_ServerReady = 0;

void jrpc_server_run(struct jrpc_server *server){
	JRPC_ServerReady = 1;
}

int jrpc_server_stop(struct jrpc_server *server) {
	JRPC_ServerReady = 0;
	return 0;
}

void jrpc_server_destroy(struct jrpc_server *server){
	/* Don't destroy server */
	int i;
	for (i = 0; i < server->procedure_count; i++){
		jrpc_procedure_destroy( &(server->procedures[i]) );
	}
	free(server->procedures);
}

static void jrpc_procedure_destroy(struct jrpc_procedure *procedure){
	if (procedure->name){
		free(procedure->name);
		procedure->name = NULL;
	}
	if (procedure->data){
		free(procedure->data);
		procedure->data = NULL;
	}
}
//注册jrpc过程
int jrpc_register_procedure(struct jrpc_server *server,
		jrpc_function function_pointer, char *name, void * data) {
	//计算RPCserver中过程数目（包含新增）
	int i = server->procedure_count++;
	//判断过程链表是否存在，不存在则创建初始节点
	if (!server->procedures)
		server->procedures = malloc(sizeof(struct jrpc_procedure));
	else {
		//过程链表存在，则调整链表空间，扩展一行
		struct jrpc_procedure * ptr = realloc(server->procedures,
				sizeof(struct jrpc_procedure) * server->procedure_count);
		//链表空间调整失败，程序退出
		if (!ptr)
			return -1;
		server->procedures = ptr;

	}
	//拷贝字符串
	if ((server->procedures[i].name = strdup(name)) == NULL)
		return -1;
	//保存过程指针
	server->procedures[i].function = function_pointer;
	//保存额外数据
	server->procedures[i].data = data;
	return 0;
}

int jrpc_deregister_procedure(struct jrpc_server *server, char *name) {
	/* Search the procedure to deregister */
	int i;
	int found = 0;
	if (server->procedures){
		for (i = 0; i < server->procedure_count; i++){
			if (found)
				server->procedures[i-1] = server->procedures[i];
			else if(!strcmp(name, server->procedures[i].name)){
				found = 1;
				jrpc_procedure_destroy( &(server->procedures[i]) );
			}
		}
		if (found){
			server->procedure_count--;
			if (server->procedure_count){
				struct jrpc_procedure * ptr = realloc(server->procedures,
					sizeof(struct jrpc_procedure) * server->procedure_count);
				if (!ptr){
					perror("realloc");
					return -1;
				}
				server->procedures = ptr;
			}else{
				server->procedures = NULL;
			}
		}
	} else {
		fprintf(stderr, "server : procedure '%s' not found\n", name);
		return -1;
	}
	return 0;
}
